//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#include "ProcessCathPDBProfile.h"
#include "PDBSeqRes.h"
#include "DBRefRecord.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <stdexcept>
#include <iostream>
#include <fstream>

#include <zlib.h>
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
using namespace std;
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#define LENGTHTEXT 500000
#define LENGTHLINE 100000
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
namespace PDBProfileSpace {

  bool AlphDomain (CathPDBProfile* cathPDBProfile, void* ref) {

    return (strcmp(cathPDBProfile->FastaProfile()->Domain()->Out(), ((CathPDBProfile*)ref)->FastaProfile()->Domain()->Out()) < 0)?true:false;

  }
  
  bool AscendentCathCode (CathPDBProfile* cathPDBProfile, void* ref) {

    return (strcmp(cathPDBProfile->FastaProfile()->CathCode()->Out(), ((CathPDBProfile*)ref)->FastaProfile()->CathCode()->Out()) < 0)?true:false;

  }
  
};
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ProcessCathPDBProfile::ProcessCathPDBProfile() {
  
  this->namefileFASTAProfile      = new String ();
  this->namefileFASTADomainLigand = new String ();

  this->locationPDB               = new String ();
  this->locationPDBAtomDomain     = new String ();
  this->locationPDBHetAtmDomain   = new String ();
  
  this->filters                   = new TListE <String> ();

  this->listDomainProfile         = new TListE <CathPDBProfile> ();
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ProcessCathPDBProfile::ProcessCathPDBProfile(const ProcessCathPDBProfile& processCathPDBProfile) {
  
  this->namefileFASTAProfile      = new String (processCathPDBProfile.namefileFASTAProfile);
  this->namefileFASTADomainLigand = new String (processCathPDBProfile.namefileFASTADomainLigand);

  this->locationPDB               = new String (processCathPDBProfile.locationPDB);
  this->locationPDBAtomDomain     = new String (processCathPDBProfile.locationPDBAtomDomain);
  this->locationPDBHetAtmDomain   = new String (processCathPDBProfile.locationPDBHetAtmDomain);
  
  this->filters                   = new TListE <String> (processCathPDBProfile.filters);

  this->listDomainProfile         = new TListE <CathPDBProfile> (processCathPDBProfile.listDomainProfile);
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ProcessCathPDBProfile::ProcessCathPDBProfile(const ProcessCathPDBProfile* processCathPDBProfile) {
  
  this->namefileFASTAProfile      = new String (processCathPDBProfile->namefileFASTAProfile);
  this->namefileFASTADomainLigand = new String (processCathPDBProfile->namefileFASTADomainLigand);

  this->locationPDB               = new String (processCathPDBProfile->locationPDB);
  this->locationPDBAtomDomain     = new String (processCathPDBProfile->locationPDBAtomDomain);
  this->locationPDBHetAtmDomain   = new String (processCathPDBProfile->locationPDBHetAtmDomain);
  
  this->filters                   = new TListE <String> (processCathPDBProfile->filters);

  this->listDomainProfile         = new TListE <CathPDBProfile> (processCathPDBProfile->listDomainProfile);
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ProcessCathPDBProfile::~ProcessCathPDBProfile() {
  
  if (this->namefileFASTAProfile)      delete this->namefileFASTAProfile;
  if (this->namefileFASTADomainLigand) delete this->namefileFASTADomainLigand;

  if (this->locationPDB)               delete this->locationPDB;
  if (this->locationPDBAtomDomain)     delete this->locationPDBAtomDomain;
  if (this->locationPDBHetAtmDomain)   delete this->locationPDBHetAtmDomain;
  
  if (this->filters)                   delete this->filters;

  if (this->listDomainProfile)         delete this->listDomainProfile;
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ProcessCathPDBProfile::NamefileFASTAProfile (String* namefileFASTAProfile) {
  
  if (namefileFASTAProfile) this->namefileFASTAProfile->In(namefileFASTAProfile);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ProcessCathPDBProfile::NamefileFASTADomainLigand (String* namefileFASTADomainLigand) {
  
  if (namefileFASTADomainLigand) this->namefileFASTADomainLigand->In(namefileFASTADomainLigand);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ProcessCathPDBProfile::LocationPDB (String* locationPDB) {
  
  if (locationPDB) this->locationPDB->In(locationPDB);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ProcessCathPDBProfile::LocationPDBAtomDomain (String* locationPDBAtomDomain) {
  
  if (locationPDBAtomDomain) this->locationPDBAtomDomain->In(locationPDBAtomDomain);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ProcessCathPDBProfile::LocationPDBHetAtmDomain (String* locationPDBHetAtmDomain) {
  
  if (locationPDBHetAtmDomain) this->locationPDBHetAtmDomain->In(locationPDBHetAtmDomain);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ProcessCathPDBProfile::Filters (TListE <String>* filters) {
  
  if (filters) *(this->filters) = *(filters);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ProcessCathPDBProfile::ListDomainProfile (TListE <CathPDBProfile>* listDomainProfile) {
  
  if (listDomainProfile) *(this->listDomainProfile) = *(listDomainProfile);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* ProcessCathPDBProfile::NamefileFASTAProfile (void) {
  
  return this->namefileFASTAProfile;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* ProcessCathPDBProfile::NamefileFASTADomainLigand (void) {
  
  return this->namefileFASTADomainLigand;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* ProcessCathPDBProfile::LocationPDB (void) {
  
  return this->locationPDB;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* ProcessCathPDBProfile::LocationPDBAtomDomain (void) {
  
  return this->locationPDBAtomDomain;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* ProcessCathPDBProfile::LocationPDBHetAtmDomain (void) {
  
  return this->locationPDBHetAtmDomain;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
TListE <String>* ProcessCathPDBProfile::Filters (void) {
  
  return this->filters;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
TListE <CathPDBProfile>* ProcessCathPDBProfile::ListDomainProfile (void) {
  
  return this->listDomainProfile;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathPDBProfile::AddFilter (String* filter) {
  
  if (!filter) return false;
  
  this->filters->Add(filter);
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathPDBProfile::AddFilter (char* filter) {
  
  if (!filter) return false;
  
  this->filters->Add(new String (filter));
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathPDBProfile::CleanFilters (void) {
  
  if (!this->filters) return false;
  
  this->filters->Clear();
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathPDBProfile::ExecuteFilters (void) {
  
  if (!this->filters) return false;
  
  this->listDomainProfile->VisibleAll();

  this->filters->SetInitial();
  
  while (this->filters->SetNext()) {
    
    if (!strcmp(this->filters->GetCurrent()->Out(), "FILTER")) {
      
      //....
      
    }
    
  }
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathPDBProfile::LoadDataFastaProfile (void) {
  
  if (!this->namefileFASTAProfile || !this->namefileFASTAProfile->Length()) return false;
  
  bool isGZFile = (this->namefileFASTAProfile->Contain("gz"))?1:0;
  
  fstream file;
  gzFile  zipFile;
  
  char    buffer [LENGTHLINE + 1];
  String* data = new String ();
  
  if (isGZFile) zipFile = gzopen (this->namefileFASTAProfile->Out(), "rb9");
  else          file.open (this->namefileFASTAProfile->Out(), fstream::in);
  
  while (!((isGZFile)?gzeof(zipFile):file.eof())) {
    
    if (isGZFile) gzgets(zipFile, buffer, LENGTHLINE);
    else          file.getline(buffer, LENGTHLINE);
    
    if (!strlen(buffer)) continue;
    
    data->Add(buffer);
    data->Add("\n");
    
    if (buffer[0] == '!') {
      
      CathPDBProfile* newCathPDBProfile = new CathPDBProfile ();
      
      if (newCathPDBProfile->FastaProfile()->ReadFromString(data)) 
        this->listDomainProfile->Add(newCathPDBProfile);
      else 
        delete newCathPDBProfile;
      
      data->In("");
      
    }
    
  }
  
  if (isGZFile) gzclose(zipFile);
  else          file.close();
  
  if (data)     delete data;
   
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathPDBProfile::CreatePDBDomainAtom (void) {
  
  if (!this->namefileFASTAProfile  || !this->namefileFASTAProfile->Length() || 
      !this->locationPDB           || !this->locationPDB->Length()          ||
      !this->locationPDBAtomDomain || !this->locationPDBAtomDomain->Length())
    return false;
  
  this->listDomainProfile->QuickSortListByArray(PDBProfileSpace::AlphDomain, NULL);
  
  this->listDomainProfile->SetInitial();
  
  char buffer [LENGTHTEXT];
  
  while (this->listDomainProfile->SetNext()) {
    
    CathPDBProfile* currentCathPDBProfile = this->listDomainProfile->GetCurrent();
    
    currentCathPDBProfile->PdbAtomDomain()->Domain(currentCathPDBProfile->FastaProfile()->Domain());
    currentCathPDBProfile->PdbAtomDomain()->Segments(currentCathPDBProfile->FastaProfile()->Segments());
    
    String* chain  = currentCathPDBProfile->PdbAtomDomain()->Domain()->SubStr(4, 5);
    String* folder = currentCathPDBProfile->PdbAtomDomain()->Domain()->SubStr(1, 3);
    String* pdb    = currentCathPDBProfile->PdbAtomDomain()->Domain()->SubStr(0, 4);

    sprintf(buffer, "%s/%s/pdb%s.ent.gz\0", this->locationPDB->Out(), folder->Out(), pdb->Out());
    currentCathPDBProfile->PdbAtomDomain()->FilenameIn()->In(buffer);
    
    sprintf(buffer, "%s/%s\0", this->locationPDBAtomDomain->Out(), currentCathPDBProfile->PdbAtomDomain()->Domain()->Out());
    currentCathPDBProfile->PdbAtomDomain()->FilenameOut()->In(buffer);
    
    if (pdb)    delete pdb;
    if (chain)  delete chain;
    if (folder) delete folder;
    
    cout << "Reading the file: " << currentCathPDBProfile->PdbAtomDomain()->FilenameIn()->Out() << endl;
    if (!currentCathPDBProfile->PdbAtomDomain()->LoadData()) {
      cout << "Error!! Problem to load the file from the PDB Database" << endl;
      continue;
    }
    
    cout << "Writing PDB ATOM Record for Domain (" << currentCathPDBProfile->PdbAtomDomain()->Domain()->Out();
    cout << ") to file: " << currentCathPDBProfile->PdbAtomDomain()->FilenameOut()->Out() << endl;
    currentCathPDBProfile->PdbAtomDomain()->OutFile();
    
    currentCathPDBProfile->PdbAtomDomain()->ListATOM()->Clear();
    currentCathPDBProfile->PdbAtomDomain()->Segments()->Clear();
    
  }
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathPDBProfile::CreatePDBDomainHetAtm (void) {
  
  if (!this->namefileFASTAProfile    || !this->namefileFASTAProfile->Length() || 
      !this->locationPDB             || !this->locationPDB->Length()          ||
      !this->locationPDBHetAtmDomain || !this->locationPDBHetAtmDomain->Length())
    return false;
  
  this->listDomainProfile->QuickSortListByArray(PDBProfileSpace::AlphDomain, NULL);
  
  this->listDomainProfile->SetInitial();
  
  char buffer [LENGTHTEXT];
  
  while (this->listDomainProfile->SetNext()) {
    
    CathPDBProfile* currentCathPDBProfile = this->listDomainProfile->GetCurrent();
    
    currentCathPDBProfile->PdbHetAtmDomain()->Domain(currentCathPDBProfile->FastaProfile()->Domain());
    
    String* chain  = currentCathPDBProfile->PdbHetAtmDomain()->Domain()->SubStr(4, 5);
    String* folder = currentCathPDBProfile->PdbHetAtmDomain()->Domain()->SubStr(1, 3);
    String* pdb    = currentCathPDBProfile->PdbHetAtmDomain()->Domain()->SubStr(0, 4);

    sprintf(buffer, "%s/%s/pdb%s.ent.gz\0", this->locationPDB->Out(), folder->Out(), pdb->Out());
    currentCathPDBProfile->PdbHetAtmDomain()->FilenameIn()->In(buffer);
    
    sprintf(buffer, "%s/%s\0", this->locationPDBHetAtmDomain->Out(), currentCathPDBProfile->PdbHetAtmDomain()->Domain()->Out());
    currentCathPDBProfile->PdbHetAtmDomain()->FilenameOut()->In(buffer);
    
    if (pdb)    delete pdb;
    if (chain)  delete chain;
    if (folder) delete folder;
    
    cout << "Reading the file: " << currentCathPDBProfile->PdbHetAtmDomain()->FilenameIn()->Out() << endl;
    if (!currentCathPDBProfile->PdbHetAtmDomain()->LoadData()) {
      cout << "Error!! Problem to load the file from the PDB Database" << endl;
      continue;
    }
    
    cout << "Writing PDB HETATM Record for Domain (" << currentCathPDBProfile->PdbHetAtmDomain()->Domain()->Out();
    cout << ") to file: " << currentCathPDBProfile->PdbHetAtmDomain()->FilenameOut()->Out() << endl;
    currentCathPDBProfile->PdbHetAtmDomain()->OutFile();
    
    currentCathPDBProfile->PdbHetAtmDomain()->ListHETATM()->Clear();
    
  }
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathPDBProfile::CreateFASTADomainLigand (double distance) {
  
  if (!this->listDomainProfile       || !this->listDomainProfile->Length()     || 
      !this->locationPDBAtomDomain   || !this->locationPDBAtomDomain->Length() ||
      !this->locationPDBHetAtmDomain || !this->locationPDBHetAtmDomain->Length())
    return false;
  
  this->listDomainProfile->QuickSortListByArray(PDBProfileSpace::AlphDomain, NULL);
  
  this->listDomainProfile->SetInitial();
  
  char buffer [LENGTHTEXT];

  while (this->listDomainProfile->SetNext()) {
    
    CathPDBProfile* currentCathPDBProfile = this->listDomainProfile->GetCurrent();
    
    currentCathPDBProfile->PdbHetAtmDomain()->Domain(currentCathPDBProfile->FastaProfile()->Domain());
    
    String* chain  = currentCathPDBProfile->PdbHetAtmDomain()->Domain()->SubStr(4, 5);
    String* folder = currentCathPDBProfile->PdbHetAtmDomain()->Domain()->SubStr(1, 3);
    String* pdb    = currentCathPDBProfile->PdbHetAtmDomain()->Domain()->SubStr(0, 4);

    sprintf(buffer, "%s/%s/pdb%s.ent.gz\0", this->locationPDB->Out(), folder->Out(), pdb->Out());
    currentCathPDBProfile->PdbHetAtmDomain()->FilenameIn()->In(buffer);
    
    sprintf(buffer, "%s/%s\0", this->locationPDBHetAtmDomain->Out(), currentCathPDBProfile->PdbHetAtmDomain()->Domain()->Out());
    currentCathPDBProfile->PdbHetAtmDomain()->FilenameOut()->In(buffer);
    
    if (pdb)    delete pdb;
    if (chain)  delete chain;
    if (folder) delete folder;
    
    cout << "Reading the file: " << currentCathPDBProfile->PdbHetAtmDomain()->FilenameIn()->Out() << endl;
    if (!currentCathPDBProfile->PdbHetAtmDomain()->LoadData()) {
      cout << "Error!! Problem to load the file from the PDB Database" << endl;
      continue;
    }
    
    cout << "Writing PDB HETATM Record for Domain (" << currentCathPDBProfile->PdbHetAtmDomain()->Domain()->Out();
    cout << ") to file: " << currentCathPDBProfile->PdbHetAtmDomain()->FilenameOut()->Out() << endl;
    currentCathPDBProfile->PdbHetAtmDomain()->OutFile();
    
    currentCathPDBProfile->PdbHetAtmDomain()->ListHETATM()->Clear();
    
  }
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathPDBProfile::CreateSeqFASTAComplete (String* filenameOut) {
  
  if (!this->listDomainProfile || !this->listDomainProfile->Length() || 
      !filenameOut             || !filenameOut->Length()             ||
      !this->locationPDB       || !this->locationPDB->Length())
    return false;
  
  char buffer [LENGTHTEXT + 1];

  bool    isGZFileOut = (filenameOut->Contain("gz"))?1:0;

  fstream fileOut;
  gzFile  zipFileOut;
  
  if (isGZFileOut) {
    zipFileOut = gzopen (filenameOut->Out(), "wb9");
    if (!zipFileOut) return false;
  }
  else {
    fileOut.open (filenameOut->Out(), fstream::out);
    if (!fileOut.is_open()) return false;
  }
  
  this->listDomainProfile->QuickSortListByArray(PDBProfileSpace::AscendentCathCode, NULL);
  
  this->listDomainProfile->SetInitial();
  while (this->listDomainProfile->SetNext()) {
    
    CathPDBProfile* currentCathPDBProfile = this->listDomainProfile->GetCurrent();
    
    String* chain  = currentCathPDBProfile->FastaProfile()->Domain()->SubStr(4, 5);
    String* folder = currentCathPDBProfile->FastaProfile()->Domain()->SubStr(1, 3);
    String* pdb    = currentCathPDBProfile->FastaProfile()->Domain()->SubStr(0, 4);

    sprintf(buffer, "%s/%s/pdb%s.ent.gz\0", this->locationPDB->Out(), folder->Out(), pdb->Out());
    cout << buffer << endl;
    
    gzFile pdbFile = gzopen(buffer, "rb9");

    if (!pdbFile) {
      cout << "Error reading the information for domain: " << currentCathPDBProfile->FastaProfile()->Domain()->Out() << endl;
      continue;
    }
    
    PDBSeqRes* pdbSeqRes = new PDBSeqRes ();
    String*    data      = new String ();
    
    cout << "Getting the data for a domain: " << currentCathPDBProfile->FastaProfile()->Domain()->Out() << endl;

    while (!gzeof(pdbFile)) {

      gzgets(pdbFile, buffer, LENGTHLINE);
      
      if ((!strncmp(buffer, "SEQRES", strlen("SEQRES"))) &&
          (buffer[11] == (chain->Out())[0])) 
        data->Add(buffer);

      if (!strncmp(buffer, "ATOM", strlen("ATOM")))
        break;

    }

    gzclose(pdbFile);
    
    if (!pdbSeqRes->ReadData(data)) {
      cout << "Error reading the information for domain: " << currentCathPDBProfile->FastaProfile()->Domain()->Out() << endl;
      continue;
    }

    cout << "Writing the complete sequence for a domain: " << currentCathPDBProfile->FastaProfile()->Domain()->Out() << endl;

    if (isGZFileOut) 
      gzprintf(zipFileOut, "%s\n%s\n", currentCathPDBProfile->FastaProfile()->ToStringHeader()->Out(), pdbSeqRes->ToStringSequence()->Out());
    else 
      fileOut << currentCathPDBProfile->FastaProfile()->ToStringHeader()->Out() << endl << pdbSeqRes->ToStringSequence()->Out() << endl;
    
    if (pdbSeqRes) delete pdbSeqRes;
    if (data)      delete data;
    if (pdb)       delete pdb;
    if (chain)     delete chain;
    if (folder)    delete folder;
    
  }
  
  if (isGZFileOut) gzclose(zipFileOut);
  else             fileOut.close();
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathPDBProfile::CreateSeqFASTACompleteUsingHeaders (String* filenameHeadersIn, String* filenameOut) {
  
  if (!filenameOut             || !filenameOut->Length()             ||
      !filenameHeadersIn       || !filenameHeadersIn->Length()       ||
      !this->locationPDB       || !this->locationPDB->Length())
    return false;
  
  char    buffer [LENGTHTEXT + 1];
  String* stringBuffer = new String ();
  bool    isGZFileOut  = (filenameOut->Contain("gz"))?1:0;

  fstream fileOut, fileIn;
  gzFile  zipFileOut;
  
  fileIn.open(filenameHeadersIn->Out(), fstream::in);
  if (!fileIn.is_open()) return false;
  
  if (isGZFileOut) {
    zipFileOut = gzopen (filenameOut->Out(), "wb9");
    if (!zipFileOut) return false;
  }
  else {
    fileOut.open (filenameOut->Out(), fstream::out);
    if (!fileOut.is_open()) return false;
  }
  
  while (!fileIn.eof()) {
    
    fileIn.getline(buffer, LENGTHTEXT);
    
    stringBuffer->In(buffer);
    
    String* chain  = stringBuffer->SubStr(5, 6);
    String* folder = stringBuffer->SubStr(2, 4);
    String* pdb    = stringBuffer->SubStr(1, 5);

    sprintf(buffer, "%s/%s/pdb%s.ent.gz\0", this->locationPDB->Out(), folder->Out(), pdb->Out());
    cout << buffer << endl;
    
    gzFile pdbFile = gzopen(buffer, "rb9");

    if (!pdbFile) {
      cout << "Error reading the information: " << stringBuffer->Out() << endl;
      continue;
    }
    
    PDBSeqRes* pdbSeqRes = new PDBSeqRes ();
    String*    data      = new String ();
    
    cout << "Getting the data for: " << stringBuffer->Out() << endl;

    while (!gzeof(pdbFile)) {

      gzgets(pdbFile, buffer, LENGTHLINE);
      
      if ((!strncmp(buffer, "SEQRES", strlen("SEQRES"))) &&
          (buffer[11] == (chain->Out())[0])) 
        data->Add(buffer);

      if (!strncmp(buffer, "ATOM", strlen("ATOM")))
        break;

    }

    gzclose(pdbFile);
    
    if (!pdbSeqRes->ReadData(data)) {
      cout << "Error reading the information: " << stringBuffer->Out() << endl;
      continue;
    }

    cout << "Writing the complete sequence for: " << stringBuffer->Out() << endl;

    if (isGZFileOut) 
      gzprintf(zipFileOut, "%s\n%s\n", stringBuffer->Out(), pdbSeqRes->ToStringSequence()->Out());
    else 
      fileOut << stringBuffer->Out() << endl << pdbSeqRes->ToStringSequence()->Out() << endl;
    
    if (pdbSeqRes) delete pdbSeqRes;
    if (data)      delete data;
    if (pdb)       delete pdb;
    if (chain)     delete chain;
    if (folder)    delete folder;
    
  }
  
  fileIn.close();
  
  if (stringBuffer) delete stringBuffer;
  
  if (isGZFileOut)  gzclose(zipFileOut);
  else              fileOut.close();
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathPDBProfile::CreateSeqFASTAInitialPosCompleteUsingHeaders (String* filenameHeadersIn, String* filenameOut) {
  
  if (!filenameOut       || !filenameOut->Length()        ||
      !filenameHeadersIn || !filenameHeadersIn->Length()  ||
      !this->locationPDB || !this->locationPDB->Length())
    return false;
  
  char    buffer [LENGTHTEXT + 1];
  String* stringBuffer = new String ();
  bool    isGZFileOut  = (filenameOut->Contain("gz"))?1:0;

  fstream fileOut, fileIn;
  gzFile  zipFileOut;
  
  fileIn.open(filenameHeadersIn->Out(), fstream::in);
  if (!fileIn.is_open()) return false;
  
  if (isGZFileOut) {
    zipFileOut = gzopen (filenameOut->Out(), "wb9");
    if (!zipFileOut) return false;
  }
  else {
    fileOut.open (filenameOut->Out(), fstream::out);
    if (!fileOut.is_open()) return false;
  }
  
  while (!fileIn.eof()) {
    
    fileIn.getline(buffer, LENGTHTEXT);
    
    stringBuffer->In(buffer);
    
    String* chain  = stringBuffer->SubStr(5, 6);
    String* folder = stringBuffer->SubStr(2, 4);
    String* pdb    = stringBuffer->SubStr(1, 5);

    sprintf(buffer, "%s/%s/pdb%s.ent.gz\0", this->locationPDB->Out(), folder->Out(), pdb->Out());
    cout << buffer << endl;
    
    gzFile pdbFile = gzopen(buffer, "rb9");

    if (!pdbFile) {
      cout << "Error reading the information: " << stringBuffer->Out() << endl;
      continue;
    }
    
    PDBSeqRes*   pdbSeqRes = new PDBSeqRes ();
    DBRefRecord* pdbDBRef  = new DBRefRecord ();
    
    String*      data      = new String ();
    
    int          startPos  = 1;
    
    cout << "Getting the data for: " << stringBuffer->Out() << endl;

    while (!gzeof(pdbFile)) {

      gzgets(pdbFile, buffer, LENGTHLINE);
      
      if (!strncmp(buffer, "DBREF", strlen("DBREF"))) {
        pdbDBRef->ReadFromString(buffer);
        if (pdbDBRef->ChainID() == (chain->Out())[0]) 
          startPos = pdbDBRef->SeqBegin();
      }
      
      if ((!strncmp(buffer, "SEQRES", strlen("SEQRES"))) &&
          (buffer[11] == (chain->Out())[0])) 
        data->Add(buffer);

      if (!strncmp(buffer, "ATOM", strlen("ATOM")))
        break;

    }

    gzclose(pdbFile);
    
    if (pdbDBRef) delete pdbDBRef;
    
    if (!pdbSeqRes->ReadData(data)) {
      cout << "Error reading the information: " << stringBuffer->Out() << endl;
      continue;
    }

    cout << "Writing the complete sequence for: " << stringBuffer->Out() << endl;

    if (isGZFileOut) 
      gzprintf(zipFileOut, "%s {%d}\n%s\n", stringBuffer->Out(), startPos, pdbSeqRes->ToStringSequence()->Out());
    else 
      fileOut << stringBuffer->Out() << " {" << startPos << "}" << endl << pdbSeqRes->ToStringSequence()->Out() << endl;
    
    if (pdbSeqRes) delete pdbSeqRes;
    if (data)      delete data;
    if (pdb)       delete pdb;
    if (chain)     delete chain;
    if (folder)    delete folder;
    
  }
  
  fileIn.close();
  
  if (stringBuffer) delete stringBuffer;
  
  if (isGZFileOut)  gzclose(zipFileOut);
  else              fileOut.close();
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
